package com.server.tools;

import com.server.config.NettyAndWebSocketConfig;
import com.server.tools.http_exception.BusinessException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Slf4j
public class PublicUtils {

    // 文件保存路径
    private static final String fileRootUrl="A:/java/idea/project/chat_file";

    /**
     * 根据收到的内容返回图片保存完整路径
     * @param image 图片样式
     * @param url 图片需要保存的文件夹路径(从服务器中文件保存的根路径开始,也就是这个代码页面中的fileRootUrl后开始)
     * @return 图片不合适则返回null,合适则返回图片完整存储路径
     */
    public static String saveImage(String image,String url){
        String type ; // 图片格式

        if(image!=null && !"".equals(image)){
            if (image.contains(";base64,")){
                String formatPart = image.substring(image.indexOf("image/") + 6, image.indexOf(";base64,"));
                if ("png".equals(formatPart)) {
                    type="png";
                } else if ("jpeg".equals(formatPart) || "jpg".equals(formatPart)) {
                    type="jpg";
                }else{
                    log.warn("图片格式异常"+image);
                    return null;
                }
                UUID uuid=UUID.randomUUID(); // 生成随机数做为名字
                setFile(url+ uuid+"."+type,image);
                return url+ uuid+"."+type; // 存储地址
            }else{
                log.warn("base64数据异常"+image);
                return null;
            }
        }else{
            log.warn("头像为空数据"+image);
            return null;
        }
    }

    /**
     * 保存图片
     * @param url 保存地址
     * @param image base64内容
     */
    public static void setFile(String url,String image){

        Path path=Paths.get(fileRootUrl+ url); // 将地址字符串转为Path,以便下面用其创建文件夹路径
        try{
            // 如果一开始没有对应文件夹路径,则直接创建好所有需要的文件夹
            // getParent会返回这个路径最后的文件前所有的目录的Path对象(就是类似这样A:\java\idea\project\chat_file),用来创建所有缺失的目录
            Files.createDirectories(path.getParent());
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(),Code.FILE_ERR);
        }

        //try自动资源管理,无论是否抛出异常都会关闭try()括号中的资源
        try (FileOutputStream randomAccessFile = new FileOutputStream(path.toFile()); // 将上面的Path转为File对象传入(相当于高级一点的地址字符串)
             FileChannel channel = randomAccessFile.getChannel()) {

            // 前缀不需要,只要后面的内容
            String imageData=image.split(",")[1];
            // 解码base64字符串为字节数组
            byte[] imageBytes =Base64.getDecoder().decode(imageData);
            // 创建合适大小的缓冲区
            ByteBuffer buffer= ByteBuffer.allocate(imageBytes.length);

            // 写入字节数组并反转指针准备将数据写入通道
            buffer.put(imageBytes);
            buffer.flip();

            // 如果一次无法全部写入则通过hasRemaining检查是否有剩余内容,有则循环写入至全部写入完成
            while (buffer.hasRemaining()){
                channel.write(buffer); // 写入内容
            }
        }  catch (IOException e) {
            throw new BusinessException(e.getMessage(),Code.FILE_ERR);
        }
    }

    /**
     * 根据传入地址获取图片并以字节数组返回
     * @param url 图片存放文件夹地址
     * @return 字节数组
     */
    public static String getFile(String url){
        if(url==null){
            return "";
        }

        ByteBuffer buffer;
        //try自动资源管理,无论是否抛出异常都会关闭try()括号中的资源
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(fileRootUrl+ url, "r");
             FileChannel channel = randomAccessFile.getChannel()) {
            // 创建合适大小的缓冲区
            buffer= ByteBuffer.allocate((int) randomAccessFile.length());
            channel.read(buffer); // 写入缓冲区
        }  catch (IOException e) {
            throw new BusinessException(e.getMessage(),Code.FILE_ERR);
        }
        return Base64.getEncoder().encodeToString(buffer.array());
    }

    /**
     * 将Date类型转换为传入格式的字符串
     * @param date Date类型日期
     * @param stringFormat 字符串日期格式
     * @return 字符串日期
     */
    public static String DateConvertString(Date date,String stringFormat){
        if(date==null || stringFormat==null){
            return  null;
        }
        // 先用toInstant方法将Date转为Instant对象再atZone转换为ZonedDateTime对象,ZoneId.systemDefault()为默认给的
        ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
        // 直接用format方法传入需要转换的DateTimeFormatter包装后的字符串格式
        return zonedDateTime.format(DateTimeFormatter.ofPattern(stringFormat));
    }


    /**
     * 将传入格式的字符串转换为Date类型
     * @param date 字符串日期
     * @param stringFormat 字符串日期格式
     * @return Date
     */
    public static Date StringConvertDate(String date,String stringFormat){
        if(date==null || stringFormat==null){
            return null;
        }
        // 将字符串日期和以DateTimeFormatter包装后的字符串格式传入LocalDateTime.parse得到操作对象
        LocalDateTime localTime = LocalDateTime.parse(date, DateTimeFormatter.ofPattern(stringFormat));
        // 用atZone(这里传入的参数默认是它).toInstant()方法转为Instant对象然后传入Date.from中
        return Date.from(localTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 将传入的数据填充进一个设置了protobuf请求头的完整HTTP响应并返回
     * @param protobuf 数据内容
     * @return 完整响应
     */
    public static ResponseEntity<byte[]> setProtobufHeader(byte[] protobuf){
        // 构建请求头对象
        HttpHeaders httpHeaders = new HttpHeaders();
        // 设置对应请求头
        httpHeaders.setContentType(MediaType.APPLICATION_PROTOBUF);
        // 封装一个完整的HTTP响应,将请求头和请求体内容都放进去并返回
        return ResponseEntity.ok().headers(httpHeaders).body(protobuf);

    }

}
